{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<font color=\"red\">注</font>: 使用 tensorboard 可视化需要安装 tensorflow (TensorBoard依赖于tensorflow库，可以任意安装tensorflow的gpu/cpu版本)\n",
    "\n",
    "```shell\n",
    "pip install tensorflow\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-07-25T06:54:07.251409900Z",
     "start_time": "2024-07-25T06:53:57.265381800Z"
    },
    "execution": {
     "iopub.execute_input": "2025-02-04T11:28:17.341649Z",
     "iopub.status.busy": "2025-02-04T11:28:17.341141Z",
     "iopub.status.idle": "2025-02-04T11:28:23.823267Z",
     "shell.execute_reply": "2025-02-04T11:28:23.822372Z",
     "shell.execute_reply.started": "2025-02-04T11:28:17.341604Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/usr/local/lib/python3.10/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n",
      "  from .autonotebook import tqdm as notebook_tqdm\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "sys.version_info(major=3, minor=10, micro=14, releaselevel='final', serial=0)\n",
      "matplotlib 3.10.0\n",
      "numpy 1.26.4\n",
      "pandas 2.2.3\n",
      "sklearn 1.6.0\n",
      "torch 2.5.1+cu124\n",
      "cuda:0\n"
     ]
    }
   ],
   "source": [
    "import matplotlib as mpl\n",
    "import matplotlib.pyplot as plt\n",
    "%matplotlib inline\n",
    "import numpy as np\n",
    "import sklearn\n",
    "import pandas as pd\n",
    "import os\n",
    "import sys\n",
    "import time\n",
    "from tqdm.auto import tqdm\n",
    "import torch\n",
    "import torch.nn as nn\n",
    "import torch.nn.functional as F\n",
    "\n",
    "print(sys.version_info)\n",
    "for module in mpl, np, pd, sklearn, torch:\n",
    "    print(module.__name__, module.__version__)\n",
    "    \n",
    "device = torch.device(\"cuda:0\") if torch.cuda.is_available() else torch.device(\"cpu\")\n",
    "print(device)\n",
    "\n",
    "seed = 42\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "jp-MarkdownHeadingCollapsed": true,
    "tags": []
   },
   "source": [
    "## 数据准备\n",
    "\n",
    "https://www.kaggle.com/competitions/cifar-10/data\n",
    "\n",
    "```shell\n",
    "$ tree -L 1 cifar-10                                    \n",
    "cifar-10\n",
    "├── sampleSubmission.csv\n",
    "├── test\n",
    "├── train\n",
    "└── trainLabels.csv\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-07-25T06:54:07.496010900Z",
     "start_time": "2024-07-25T06:54:07.256405800Z"
    },
    "ExecutionIndicator": {
     "show": true
    },
    "execution": {
     "iopub.execute_input": "2025-02-04T11:30:32.056660Z",
     "iopub.status.busy": "2025-02-04T11:30:32.056152Z",
     "iopub.status.idle": "2025-02-04T11:30:34.965444Z",
     "shell.execute_reply": "2025-02-04T11:30:34.964500Z",
     "shell.execute_reply.started": "2025-02-04T11:30:32.056626Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[(PosixPath('competitions/cifar-10/train/1.png'), 'frog'),\n",
      " (PosixPath('competitions/cifar-10/train/2.png'), 'truck'),\n",
      " (PosixPath('competitions/cifar-10/train/3.png'), 'truck'),\n",
      " (PosixPath('competitions/cifar-10/train/4.png'), 'deer'),\n",
      " (PosixPath('competitions/cifar-10/train/5.png'), 'automobile')]\n",
      "[(PosixPath('competitions/cifar-10/test/1.png'), 'cat'),\n",
      " (PosixPath('competitions/cifar-10/test/2.png'), 'cat'),\n",
      " (PosixPath('competitions/cifar-10/test/3.png'), 'cat'),\n",
      " (PosixPath('competitions/cifar-10/test/4.png'), 'cat'),\n",
      " (PosixPath('competitions/cifar-10/test/5.png'), 'cat')]\n",
      "50000 300000\n"
     ]
    }
   ],
   "source": [
    "from pathlib import Path\n",
    "\n",
    "DATA_DIR = Path(\".\")\n",
    "DATA_DIR1 =Path(\"competitions/cifar-10/\")\n",
    "train_lables_file = DATA_DIR / \"trainLabels.csv\"\n",
    "test_csv_file = DATA_DIR / \"sampleSubmission.csv\" #测试集模板csv文件\n",
    "train_folder = DATA_DIR1 / \"train\"\n",
    "test_folder = DATA_DIR1 / \"test\"\n",
    "\n",
    "\n",
    "#所有的类别\n",
    "class_names = [\n",
    "    'airplane',\n",
    "    'automobile',\n",
    "    'bird',\n",
    "    'cat',\n",
    "    'deer',\n",
    "    'dog',\n",
    "    'frog',\n",
    "    'horse',\n",
    "    'ship',\n",
    "    'truck',\n",
    "]\n",
    "\n",
    "def parse_csv_file(filepath, folder):\n",
    "    \"\"\"Parses csv files into (filename(path), label) format\"\"\"\n",
    "    results = []\n",
    "    #读取所有行\n",
    "    with open(filepath, 'r') as f:\n",
    "#         lines = f.readlines()  为什么加[1:]，可以试这个\n",
    "        #第一行不需要，因为第一行是标签\n",
    "        lines = f.readlines()[1:] \n",
    "    for line in lines:#依次去取每一行\n",
    "        image_id, label_str = line.strip('\\n').split(',')\n",
    "        image_full_path = folder / f\"{image_id}.png\"\n",
    "        results.append((image_full_path, label_str)) #得到对应图片的路径和分类\n",
    "    return results\n",
    "\n",
    "#解析对应的文件夹\n",
    "train_labels_info = parse_csv_file(train_lables_file, train_folder)\n",
    "test_csv_info = parse_csv_file(test_csv_file, test_folder)\n",
    "#打印\n",
    "import pprint\n",
    "pprint.pprint(train_labels_info[0:5])\n",
    "pprint.pprint(test_csv_info[0:5])\n",
    "print(len(train_labels_info), len(test_csv_info))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-02-04T11:30:34.967201Z",
     "iopub.status.busy": "2025-02-04T11:30:34.966784Z",
     "iopub.status.idle": "2025-02-04T11:30:35.063894Z",
     "shell.execute_reply": "2025-02-04T11:30:35.063022Z",
     "shell.execute_reply.started": "2025-02-04T11:30:34.967170Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "                            filepath       class\n",
      "0  competitions/cifar-10/train/1.png        frog\n",
      "1  competitions/cifar-10/train/2.png       truck\n",
      "2  competitions/cifar-10/train/3.png       truck\n",
      "3  competitions/cifar-10/train/4.png        deer\n",
      "4  competitions/cifar-10/train/5.png  automobile\n",
      "                                filepath       class\n",
      "0  competitions/cifar-10/train/45001.png       horse\n",
      "1  competitions/cifar-10/train/45002.png  automobile\n",
      "2  competitions/cifar-10/train/45003.png        deer\n",
      "3  competitions/cifar-10/train/45004.png  automobile\n",
      "4  competitions/cifar-10/train/45005.png    airplane\n",
      "                           filepath class\n",
      "0  competitions/cifar-10/test/1.png   cat\n",
      "1  competitions/cifar-10/test/2.png   cat\n",
      "2  competitions/cifar-10/test/3.png   cat\n",
      "3  competitions/cifar-10/test/4.png   cat\n",
      "4  competitions/cifar-10/test/5.png   cat\n"
     ]
    }
   ],
   "source": [
    "# train_df = pd.DataFrame(train_labels_info)\n",
    "train_df = pd.DataFrame(train_labels_info[0:45000])\n",
    "valid_df = pd.DataFrame(train_labels_info[45000:])\n",
    "test_df = pd.DataFrame(test_csv_info)\n",
    "\n",
    "train_df.columns = ['filepath', 'class']\n",
    "valid_df.columns = ['filepath', 'class']\n",
    "test_df.columns = ['filepath', 'class']\n",
    "\n",
    "print(train_df.head())\n",
    "print(valid_df.head())\n",
    "print(test_df.head())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-02-04T11:30:35.065394Z",
     "iopub.status.busy": "2025-02-04T11:30:35.064972Z",
     "iopub.status.idle": "2025-02-04T11:30:37.642749Z",
     "shell.execute_reply": "2025-02-04T11:30:37.641853Z",
     "shell.execute_reply.started": "2025-02-04T11:30:35.065364Z"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "from PIL import Image\n",
    "from torch.utils.data import Dataset, DataLoader\n",
    "from torchvision import transforms\n",
    "\n",
    "class Cifar10Dataset(Dataset):\n",
    "    df_map = {\n",
    "        \"train\": train_df,\n",
    "        \"eval\": valid_df,\n",
    "        \"test\": test_df\n",
    "    }\n",
    "    label_to_idx = {label: idx for idx, label in enumerate(class_names)} #将类别转换为数字\n",
    "    idx_to_label = {idx: label for idx, label in enumerate(class_names)}#将数字转换为类别\n",
    "    def __init__(self, mode, transform=None):\n",
    "        self.df = self.df_map.get(mode, None)\n",
    "        if self.df is None:\n",
    "            raise ValueError(\"mode should be one of train, val, test, but got {}\".format(mode))\n",
    "\n",
    "        self.transform = transform #对图片进行变换，transform是一个函数\n",
    "        \n",
    "    def __getitem__(self, index):\n",
    "        img_path, label = self.df.iloc[index]#得到对应的图片路径和类别\n",
    "        img = Image.open(img_path).convert('RGB')#打开图片\n",
    "        # # img 转换为 channel first\n",
    "        # img = img.transpose((2, 0, 1))\n",
    "        # transform\n",
    "        img = self.transform(img) #对图片进行变换\n",
    "        # label 转换为 idx\n",
    "        label = self.label_to_idx[label]\n",
    "        return img, label #返回图片和类别\n",
    "    \n",
    "    def __len__(self):\n",
    "        return self.df.shape[0]\n",
    "    \n",
    "IMAGE_SIZE = 32\n",
    "mean, std = [0.4914, 0.4822, 0.4465], [0.247, 0.243, 0.261]\n",
    "\n",
    "transforms_train = transforms.Compose([\n",
    "        # resize\n",
    "        transforms.Resize((IMAGE_SIZE, IMAGE_SIZE)),\n",
    "        # random rotation 40\n",
    "        transforms.RandomRotation(40),\n",
    "        # horizaontal flip\n",
    "        transforms.RandomHorizontalFlip(),\n",
    "        transforms.ToTensor(),\n",
    "        transforms.Normalize(mean, std)\n",
    "    ])\n",
    "\n",
    "transforms_eval = transforms.Compose([\n",
    "        # resize\n",
    "        transforms.Resize((IMAGE_SIZE, IMAGE_SIZE)),\n",
    "        transforms.ToTensor(),\n",
    "        transforms.Normalize(mean, std)\n",
    "    ])\n",
    "\n",
    "train_ds = Cifar10Dataset(\"train\", transforms_train)\n",
    "eval_ds = Cifar10Dataset(\"eval\", transforms_eval) "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-02-04T11:30:37.644698Z",
     "iopub.status.busy": "2025-02-04T11:30:37.644223Z",
     "iopub.status.idle": "2025-02-04T11:30:37.649206Z",
     "shell.execute_reply": "2025-02-04T11:30:37.648370Z",
     "shell.execute_reply.started": "2025-02-04T11:30:37.644666Z"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "batch_size = 64\n",
    "train_dl = DataLoader(train_ds, batch_size=batch_size, shuffle=True, num_workers=4)   \n",
    "eval_dl = DataLoader(eval_ds, batch_size=batch_size, shuffle=False, num_workers=4)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 遍历train_ds得到每张图片，计算每个通道的均值和方差\n",
    "# def cal_mean_std(ds):\n",
    "#     mean = 0.\n",
    "#     std = 0.\n",
    "#     for img, _ in ds:\n",
    "#         mean += img.mean(dim=(1, 2))\n",
    "#         std += img.std(dim=(1, 2))\n",
    "#     mean /= len(ds)\n",
    "#     std /= len(ds)\n",
    "#     return mean, std\n",
    "#\n",
    "# # 经过 normalize 后 均值为0，方差为1\n",
    "# print(cal_mean_std(train_ds))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "tags": []
   },
   "source": [
    "## 定义模型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-07-25T07:01:50.235242700Z",
     "start_time": "2024-07-25T07:01:50.218212400Z"
    },
    "ExecutionIndicator": {
     "show": true
    },
    "execution": {
     "iopub.execute_input": "2025-02-04T11:46:33.247793Z",
     "iopub.status.busy": "2025-02-04T11:46:33.246964Z",
     "iopub.status.idle": "2025-02-04T11:46:33.264033Z",
     "shell.execute_reply": "2025-02-04T11:46:33.263310Z",
     "shell.execute_reply.started": "2025-02-04T11:46:33.247750Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "             model.0.weight             paramerters num: 864\n",
      "              model.0.bias              paramerters num: 32\n",
      "             model.2.weight             paramerters num: 9216\n",
      "              model.2.bias              paramerters num: 32\n",
      "             model.5.weight             paramerters num: 9216\n",
      "              model.5.bias              paramerters num: 32\n",
      "             model.7.weight             paramerters num: 9216\n",
      "              model.7.bias              paramerters num: 32\n",
      "            model.10.weight             paramerters num: 9216\n",
      "             model.10.bias              paramerters num: 32\n",
      "            model.12.weight             paramerters num: 9216\n",
      "             model.12.bias              paramerters num: 32\n",
      "               cls.weight               paramerters num: 5120\n",
      "                cls.bias                paramerters num: 10\n"
     ]
    }
   ],
   "source": [
    "class VGG(nn.Module):\n",
    "    def __init__(self, num_classes):\n",
    "        super().__init__()\n",
    "        self.model = nn.Sequential(\n",
    "            nn.Conv2d(in_channels=3, out_channels=32, kernel_size=3, padding=\"same\"),\n",
    "            nn.ReLU(),\n",
    "            nn.Conv2d(in_channels=32, out_channels=32, kernel_size=3, padding=\"same\"),\n",
    "            nn.ReLU(),\n",
    "            nn.MaxPool2d(kernel_size=2),\n",
    "            nn.Conv2d(in_channels=32, out_channels=32, kernel_size=3, padding=\"same\"),\n",
    "            nn.ReLU(),\n",
    "            nn.Conv2d(in_channels=32, out_channels=32, kernel_size=3, padding=\"same\"),\n",
    "            nn.ReLU(),\n",
    "            nn.MaxPool2d(kernel_size=2),\n",
    "            nn.Conv2d(in_channels=32, out_channels=32, kernel_size=3, padding=\"same\"),\n",
    "            nn.ReLU(),\n",
    "            nn.Conv2d(in_channels=32, out_channels=32, kernel_size=3, padding=\"same\"),\n",
    "            nn.ReLU(),\n",
    "            nn.MaxPool2d(kernel_size=2),\n",
    "            nn.Flatten(),\n",
    "        )\n",
    "\n",
    "        self.cls = nn.Linear(512, num_classes)\n",
    "\n",
    "        self.init_weights()\n",
    "\n",
    "\n",
    "    def init_weights(self):\n",
    "        \"\"\"使用 xavier 均匀分布来初始化全连接层、卷积层的权重 W\"\"\"\n",
    "        for m in self.modules():\n",
    "            if isinstance(m, (nn.Linear, nn.Conv2d)):\n",
    "                nn.init.xavier_uniform_(m.weight)\n",
    "                nn.init.zeros_(m.bias)\n",
    "\n",
    "    @classmethod  # 类方法\n",
    "    def from_pretrained(cls, ckpt_path, num_classes=10):  # 加载预训练接口\n",
    "        state_dict = torch.load(ckpt_path, weights_only =True,  map_location=\"cpu\")  # 加载模型\n",
    "\n",
    "        # 希望模型最后两层的参数是还是随机的\n",
    "\n",
    "        state_dict.pop(\"cls.weight\")  # 去掉最后一层的权重，cls就是vgg自己\n",
    "        state_dict.pop(\"cls.bias\")  # 去掉最后一层的偏置\n",
    "        \n",
    "        # 去掉最后三层的权重和偏置\n",
    "        state_dict.pop(\"model.12.weight\")\n",
    "        state_dict.pop(\"model.12.bias\")\n",
    "        state_dict.pop(\"model.10.weight\")\n",
    "        state_dict.pop(\"model.10.bias\")\n",
    "\n",
    "        model = cls(num_classes=num_classes)  # 重新实例化模型\n",
    "        # 将修改后的状态字典加载到新创建的模型实例中。\n",
    "        # 参数strict=False表示在加载状态字典时，如果字典中存在模型不期望的键或缺少某些期望的键，将不会抛出错误。\n",
    "        # 这在迁移学习中很有用，因为你可能希望覆盖或忽略一些权重。\n",
    "        model.load_state_dict(state_dict, strict=False)  # 加载模型参数\n",
    "\n",
    "        return model\n",
    "\n",
    "    def forward(self, x):\n",
    "        features = self.model(x)\n",
    "        return self.cls(features)\n",
    "\n",
    "\n",
    "for key, value in VGG(len(class_names)).named_parameters():\n",
    "    print(f\"{key:^40}paramerters num: {np.prod(value.shape)}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2024-07-25T07:09:22.216355600Z",
     "start_time": "2024-07-25T07:09:22.205361600Z"
    },
    "collapsed": false,
    "execution": {
     "iopub.execute_input": "2025-02-04T11:30:43.952234Z",
     "iopub.status.busy": "2025-02-04T11:30:43.951738Z",
     "iopub.status.idle": "2025-02-04T11:30:43.960701Z",
     "shell.execute_reply": "2025-02-04T11:30:43.959915Z",
     "shell.execute_reply.started": "2025-02-04T11:30:43.952199Z"
    },
    "jupyter": {
     "outputs_hidden": false
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'generator'>\n",
      "             model.0.weight             paramerters num: 864\n",
      "              model.0.bias              paramerters num: 32\n",
      "             model.2.weight             paramerters num: 9216\n",
      "              model.2.bias              paramerters num: 32\n",
      "             model.5.weight             paramerters num: 9216\n",
      "              model.5.bias              paramerters num: 32\n",
      "             model.7.weight             paramerters num: 9216\n",
      "              model.7.bias              paramerters num: 32\n",
      "            model.10.weight             paramerters num: 9216\n",
      "             model.10.bias              paramerters num: 32\n",
      "            model.12.weight             paramerters num: 9216\n",
      "             model.12.bias              paramerters num: 32\n",
      "               cls.weight               paramerters num: 5120\n",
      "                cls.bias                paramerters num: 10\n"
     ]
    }
   ],
   "source": [
    "model=VGG(len(class_names))\n",
    "print(type(model.named_parameters()))\n",
    "for key, value in  model.named_parameters():\n",
    "    print(f\"{key:^40}paramerters num: {np.prod(value.shape)}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 训练\n",
    "\n",
    "pytorch的训练需要自行实现，包括\n",
    "1. 定义损失函数\n",
    "2. 定义优化器\n",
    "3. 定义训练步\n",
    "4. 训练"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "jp-MarkdownHeadingCollapsed": true,
    "tags": []
   },
   "source": [
    "### evaluating"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-02-04T11:30:47.326234Z",
     "iopub.status.busy": "2025-02-04T11:30:47.325740Z",
     "iopub.status.idle": "2025-02-04T11:30:47.441704Z",
     "shell.execute_reply": "2025-02-04T11:30:47.440918Z",
     "shell.execute_reply.started": "2025-02-04T11:30:47.326199Z"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "from sklearn.metrics import accuracy_score\n",
    "\n",
    "@torch.no_grad()\n",
    "def evaluating(model, dataloader, loss_fct):\n",
    "    loss_list = []\n",
    "    pred_list = []\n",
    "    label_list = []\n",
    "    for datas, labels in dataloader:\n",
    "        datas = datas.to(device)\n",
    "        labels = labels.to(device)\n",
    "        # 前向计算\n",
    "        logits = model(datas)\n",
    "        loss = loss_fct(logits, labels)         # 验证集损失\n",
    "        loss_list.append(loss.item())\n",
    "        \n",
    "        preds = logits.argmax(axis=-1)    # 验证集预测\n",
    "        pred_list.extend(preds.cpu().numpy().tolist())\n",
    "        label_list.extend(labels.cpu().numpy().tolist())\n",
    "        \n",
    "    acc = accuracy_score(label_list, pred_list)\n",
    "    return np.mean(loss_list), acc"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "jp-MarkdownHeadingCollapsed": true,
    "tags": []
   },
   "source": [
    "### Save Best\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-02-04T11:30:52.434249Z",
     "iopub.status.busy": "2025-02-04T11:30:52.433600Z",
     "iopub.status.idle": "2025-02-04T11:30:52.441190Z",
     "shell.execute_reply": "2025-02-04T11:30:52.440410Z",
     "shell.execute_reply.started": "2025-02-04T11:30:52.434211Z"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "class SaveCheckpointsCallback:\n",
    "    def __init__(self, save_dir, save_step=5000, save_best_only=True):\n",
    "        \"\"\"\n",
    "        Save checkpoints each save_epoch epoch. \n",
    "        We save checkpoint by epoch in this implementation.\n",
    "        Usually, training scripts with pytorch evaluating model and save checkpoint by step.\n",
    "\n",
    "        Args:\n",
    "            save_dir (str): dir to save checkpoint\n",
    "            save_epoch (int, optional): the frequency to save checkpoint. Defaults to 1.\n",
    "            save_best_only (bool, optional): If True, only save the best model or save each model at every epoch.\n",
    "        \"\"\"\n",
    "        self.save_dir = save_dir\n",
    "        self.save_step = save_step\n",
    "        self.save_best_only = save_best_only\n",
    "        self.best_metrics = -1\n",
    "        \n",
    "        # mkdir\n",
    "        if not os.path.exists(self.save_dir):\n",
    "            os.mkdir(self.save_dir)\n",
    "        \n",
    "    def __call__(self, step, state_dict, metric=None):\n",
    "        if step % self.save_step > 0:\n",
    "            return\n",
    "        \n",
    "        if self.save_best_only:\n",
    "            assert metric is not None\n",
    "            if metric >= self.best_metrics:\n",
    "                # save checkpoints\n",
    "                torch.save(state_dict, os.path.join(self.save_dir, \"best.ckpt\"))\n",
    "                # update best metrics\n",
    "                self.best_metrics = metric\n",
    "        else:\n",
    "            torch.save(state_dict, os.path.join(self.save_dir, f\"{step}.ckpt\"))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "jp-MarkdownHeadingCollapsed": true,
    "tags": []
   },
   "source": [
    "### Early Stop"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-02-04T11:30:53.705071Z",
     "iopub.status.busy": "2025-02-04T11:30:53.704557Z",
     "iopub.status.idle": "2025-02-04T11:30:53.711071Z",
     "shell.execute_reply": "2025-02-04T11:30:53.710208Z",
     "shell.execute_reply.started": "2025-02-04T11:30:53.705037Z"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "class EarlyStopCallback:\n",
    "    def __init__(self, patience=5, min_delta=0.01):\n",
    "        \"\"\"\n",
    "\n",
    "        Args:\n",
    "            patience (int, optional): Number of epochs with no improvement after which training will be stopped.. Defaults to 5.\n",
    "            min_delta (float, optional): Minimum change in the monitored quantity to qualify as an improvement, i.e. an absolute \n",
    "                change of less than min_delta, will count as no improvement. Defaults to 0.01.\n",
    "        \"\"\"\n",
    "        self.patience = patience\n",
    "        self.min_delta = min_delta\n",
    "        self.best_metric = -1\n",
    "        self.counter = 0\n",
    "        \n",
    "    def __call__(self, metric):\n",
    "        if metric >= self.best_metric + self.min_delta:\n",
    "            # update best metric\n",
    "            self.best_metric = metric\n",
    "            # reset counter \n",
    "            self.counter = 0\n",
    "        else: \n",
    "            self.counter += 1\n",
    "            \n",
    "    @property\n",
    "    def early_stop(self):\n",
    "        return self.counter >= self.patience"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "tags": []
   },
   "source": [
    "### training"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {
    "ExecutionIndicator": {
     "show": true
    },
    "execution": {
     "iopub.execute_input": "2025-02-04T11:46:50.828289Z",
     "iopub.status.busy": "2025-02-04T11:46:50.827495Z",
     "iopub.status.idle": "2025-02-04T11:48:40.293400Z",
     "shell.execute_reply": "2025-02-04T11:48:40.292341Z",
     "shell.execute_reply.started": "2025-02-04T11:46:50.828251Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "100%|██████████| 7040/7040 [01:49<00:00, 64.33it/s, epoch=9]\n"
     ]
    }
   ],
   "source": [
    "# 训练\n",
    "def training(\n",
    "    model, \n",
    "    train_loader, \n",
    "    val_loader, \n",
    "    epoch, \n",
    "    loss_fct, \n",
    "    optimizer, \n",
    "    save_ckpt_callback=None,\n",
    "    early_stop_callback=None,\n",
    "    eval_step=500,\n",
    "    ):\n",
    "    record_dict = {\n",
    "        \"train\": [],\n",
    "        \"val\": []\n",
    "    }\n",
    "    \n",
    "    global_step = 0\n",
    "    model.train()\n",
    "    with tqdm(total=epoch * len(train_loader)) as pbar:\n",
    "        for epoch_id in range(epoch):\n",
    "            # training\n",
    "            for datas, labels in train_loader:\n",
    "                datas = datas.to(device)\n",
    "                labels = labels.to(device)\n",
    "                # 梯度清空\n",
    "                optimizer.zero_grad()\n",
    "                # 模型前向计算\n",
    "                logits = model(datas)\n",
    "                # 计算损失\n",
    "                loss = loss_fct(logits, labels)\n",
    "                # 梯度回传\n",
    "                loss.backward()\n",
    "                # 调整优化器，包括学习率的变动等\n",
    "                optimizer.step()\n",
    "                preds = logits.argmax(axis=-1)\n",
    "            \n",
    "                acc = accuracy_score(labels.cpu().numpy(), preds.cpu().numpy())    \n",
    "                loss = loss.cpu().item()\n",
    "                # record\n",
    "                \n",
    "                record_dict[\"train\"].append({\n",
    "                    \"loss\": loss, \"acc\": acc, \"step\": global_step\n",
    "                })\n",
    "                \n",
    "                # evaluating\n",
    "                if global_step % eval_step == 0:\n",
    "                    model.eval()\n",
    "                    val_loss, val_acc = evaluating(model, val_loader, loss_fct)\n",
    "                    record_dict[\"val\"].append({\n",
    "                        \"loss\": val_loss, \"acc\": val_acc, \"step\": global_step\n",
    "                    })\n",
    "                    model.train()\n",
    "                    \n",
    "                    # 2. 保存模型权重 save model checkpoint\n",
    "                    if save_ckpt_callback is not None:\n",
    "                        save_ckpt_callback(global_step, model.state_dict(), metric=val_acc)\n",
    "\n",
    "                    # 3. 早停 Early Stop\n",
    "                    if early_stop_callback is not None:\n",
    "                        early_stop_callback(val_acc)\n",
    "                        if early_stop_callback.early_stop:\n",
    "                            print(f\"Early stop at epoch {epoch_id} / global_step {global_step}\")\n",
    "                            return record_dict\n",
    "                    \n",
    "                # udate step\n",
    "                global_step += 1\n",
    "                pbar.update(1)\n",
    "                pbar.set_postfix({\"epoch\": epoch_id})\n",
    "        \n",
    "    return record_dict\n",
    "        \n",
    "\n",
    "epoch = 10\n",
    "model = VGG(num_classes=10) #第一次先训练，得到下面best.ckpt后，再注释这一条，用下面的加载模型\n",
    "\n",
    "# 1. 定义损失函数 采用交叉熵损失\n",
    "loss_fct = nn.CrossEntropyLoss()\n",
    "# 2. 定义优化器 采用 adam\n",
    "optimizer = torch.optim.Adam(model.parameters(), lr=0.001)\n",
    "\n",
    "exp_name = \"vgg-fine-tune\"\n",
    "\n",
    "# 2. save best\n",
    "if not os.path.exists(\"checkpoints\"):\n",
    "    os.makedirs(\"checkpoints\")\n",
    "\n",
    "save_ckpt_callback = SaveCheckpointsCallback(f\"checkpoints/{exp_name}\", save_step=len(train_dl), save_best_only=True)\n",
    "# 3. early stop\n",
    "early_stop_callback = EarlyStopCallback(patience=5)\n",
    "\n",
    "model = model.to(device)\n",
    "record = training(\n",
    "    model, \n",
    "    train_dl, \n",
    "    eval_dl, \n",
    "    epoch, \n",
    "    loss_fct, \n",
    "    optimizer, \n",
    "    save_ckpt_callback=save_ckpt_callback,\n",
    "    early_stop_callback=early_stop_callback,\n",
    "    eval_step=len(train_dl)\n",
    "    )"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "tags": []
   },
   "source": [
    "### 绘图"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-02-04T11:58:29.911467Z",
     "iopub.status.busy": "2025-02-04T11:58:29.910927Z",
     "iopub.status.idle": "2025-02-04T11:58:30.236581Z",
     "shell.execute_reply": "2025-02-04T11:58:30.235787Z",
     "shell.execute_reply.started": "2025-02-04T11:58:29.911427Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAzwAAAHACAYAAABnOW2lAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjAsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvlHJYcgAAAAlwSFlzAAAPYQAAD2EBqD+naQABAABJREFUeJzsnXd8W/XV/99X2/JecZzp7Akh7BAIKwPSUigtpZQ+KdCW0gKlzQ+eNh0U6EhLKaWDlg5Wy2xZTwshJARCEggJBMLKns6w471kWfP+/ri6V5Il2ZItD8Xn/Xr5Fevq3qsjWZG+n3vO+RxFVVUVQRAEQRAEQRCE4xDTQAcgCIIgCIIgCILQV4jgEQRBEARBEAThuEUEjyAIgiAIgiAIxy0ieARBEARBEARBOG4RwSMIgiAIgiAIwnGLCB5BEARBEARBEI5bRPAIgiAIgiAIgnDcIoJHEARBEARBEITjFstAB5AMwWCQo0ePkpubi6IoAx2OIAjCkEFVVVpbWxkxYgQmk1wji0S+mwRBEAaGVL+bMkLwHD16lNGjRw90GIIgCEOWQ4cOMWrUqIEOY1Ah302CIAgDS7LfTRkheHJzcwHtSeXl5aV8vM/nY9WqVSxcuBCr1Zru8PqMTIw7E2MGibu/ycS4MzFm6H3cLS0tjB492vgcFsIMxe+mTIwZJO7+JhPjzsSYYejGnep3U0YIHr1UIC8vr8dfKk6nk7y8vIx7M2Ra3JkYM0jc/U0mxp2JMUP64paSrViG4ndTJsYMEnd/k4lxZ2LMIHEn+90kBdmCIAiCIAiCIBy3iOARBEEQBEEQBOG4RQSPIAiCIAiCIAjHLRnRwyMIwuBEVVX8fj+BQCCl43w+HxaLhY6OjpSPHSgyMWboPm6z2YzFYpEeHUEQBOG4RQSPIAg9wuv1UlVVRXt7e8rHqqrK8OHDOXToUMYstDMxZkgubqfTSXl5OTabrZ+jEwRBEIS+RwSPIAgpEwwG2b9/P2azmREjRmCz2VISAcFgkLa2NnJycjJmmGUmxgxdx62qKl6vl9raWvbv38+kSZMy6rkJgiAIQjKI4BEEIWW8Xi/BYJDRo0fjdDpTPj4YDOL1enE4HBmzwM7EmKH7uLOysrBarRw8eNDYTxAEQRCOJzLnW1sQhEFHJi38hcTI31EQBEE4npFvOUEQBEEQBEEQjltE8AiCIAiCIAiCcNwigkcQBKGHVFRUcN9996XlXGvXrkVRFJqamtJyPkEQBEEQNMS0QBCEIcV5553HSSedlBah8s4775Cdnd37oARBEARB6DNE8AiCIESgqiqBQACLpfuPx9LS0n6ISBAEQRCE3nDcl7TV795M7e/OY+rHvxzoUAThuEZVVdq9/qR/3N5ASvsn+lFVNekYr7nmGt544w1+97vfoSgKiqLwyCOPoCgKL7/8Mqeccgp2u50NGzawd+9eLr30UsrKysjJyeGMM85g7dq1UefrXNKmKAp///vf+exnP4vT6WTSpEn85z//6fFr+uyzzzJjxgzsdjsVFRX85je/ibr/T3/6E5MmTcLhcFBWVsbnP/95475nnnmGE044gezsbMaPH8/ChQtxuVw9jkUQBEGI5d5VO1n23IcpfRfF4/WdNSx5aDNVze40RSZEctxneBp8Fia1fYxbtYMaHOhwBOG4xe0LMP32V/r9cbfdtQinLbmPst/97nfs2rWLmTNnctdddwHwySefAPD973+fe+65h/Hjx1NYWMihQ4dYvHgxP//5z7Hb7Tz66KNcddVVbN++nYqKioSPceedd3L33Xfz61//mj/84Q9cffXVHDx4kKKiopSe15YtW/jCF77AHXfcwZVXXslbb73Ft771LYqLi7nmmmt49913+fa3v80///lPzjrrLBoaGli/fj0AVVVVXHXVVdx9991ceumlVFVVsXXr1l5/IQuCIAhhAkGVP7y+B1WFmy+YxIiCrB6f68lNlazbVcsrH1dzzdxxaYxSgCEgeMzF4/GoFrIUD76mShg2aaBDEgRhgMjPz8dms+F0Ohk+fDgAO3bsAOCuu+5iwYIFxr5FRUXMmjXLuH3XXXfx7LPP8t///pebb7454WNcc801XHXVVQD84he/4Pe//z2bN2/moosuSinWe++9lwsvvJAf//jHAEyePJlt27bx61//mmuuuYbKykqys7P59Kc/TW5uLmPHjmX27NmAJnj8fj+XX345o0ePpqioiDlz5si8HUEQhDTS4vahX0dq7fD36lxuXwCAhnZfb8MS4nDcCx6H3c4+dQTTlEqU2h0ieAShj8iymtl216Kk9g0Gg7S2tJKbl9vrRXiW1dyr43VOPfXUqNttbW3ccccdvPTSS4aAcLvdVFZWdnmeE0880fg9OzubvLw8ampqUo5n+/btXHrppVHb5s6dy3333UcgEGDBggWMHTuW8ePHc9FFF3HRRRcZpXSzZs3iwgsv5IQTTmDhwoWcc845fPnLX6a4uDjlOARBEIT4NLnD4qS1o3dCxePTqpAaXd5enUeIz3F/uS/LamaXOgoAtXbHAEcjCMcviqLgtFmS/smymVPaP9GPoihpib+z29qtt97K888/zy9+8QvWr1/Pe++9x/Tp0/F6u/4yslqtMa9LMJj+ctrc3Fzee+89nnzyScrLy7n99tuZNWsWTU1NmM1mVq9ezcsvv8z06dP561//yrRp09i/f3/a4xAEQRiqNLWHvw9aPb3L8Hj8oQyPCJ4+4bgXPA6rmV3BkOCpEcEjCEMdm81GIBDodr8333yTa665hs9+9rOccMIJDB8+vNvsTjqZNm0ab775ZkxMkydPxmzWsloWi4X58+dz99138+GHH3LgwAFee+01QBNac+fO5Y477mDdunXYbDaef/75fotfEATheCcyw9PWy5K2jlCGRwRP33Dcl7TZLSZ2qyMBtJI2QRCGNBUVFWzatIkDBw6Qk5OTMPsyadIknnvuOS655BIUReFHP/pRvzb9/7//9/847bTT+OlPf8qVV17Jxo0b+eMf/8if/vQnAF588UX27dvHvHnzKCwsZMWKFQSDQaZMmcKmTZtYs2YNCxcupKSkhLVr11JbW8u0adP6LX5BEITjnZZIwZOmDE9juwievuC4z/CYTAoHTGMAMDfshmD3V3YFQTh+ufXWWzGbzUyfPp3S0tKEWZt7772XwsJCzjrrLC655BIWLVoU1Z/T15x88sn861//4qmnnmLmzJncfvvt3HXXXVxzzTUAFBQU8Nxzz3HBBRcwbdo0HnjgAZ588klmzJhBXl4e69atY/HixUydOpWf//zn3HPPPVx88cX9Fr8gCMLxTlN7+jI8Hr9kePqS4z7DA1BrKadDteIIeKDxABRPGOiQBEEYICZPnszGjRujtukiIpKKigqjPAw0o4Uvf/nL5OXlGdsOHDgQdUy8DFBTU1NScZ133nkxx3/uc5/jc5/7XNz9zz777Ji5QDrTpk1j5cqVRtwtLS1RcQuCIAwlth5qYtvRFq46fXTa+j4hWvD0toenwxfO8KiqmtY4hSGQ4QGw2azsVUdoN6SsTRAEQRAEYciw9F9b+cHzH/Hh4ea0nrc5jT08eobHF1B7LZ6EWIaE4HFYwk5t1Gwf2GAEQRiS3HDDDeTk5MT9ueGGGwY6PEEQhOMSrz/IgToXAAcb2tN67iZ3hEtbb22p/eF+UrGmTj9DoqTNYTWxOzgKzEiGRxCEAeGuu+7i1ltvjXuflJsJgiD0DUea3ARD1cLVze60nru5PT2mBb5AkEAwXNLc4PIytji7iyOEVBkigicywyOCRxCE/mfYsGEMGzZsoMMQBEEYUhyodxm/H23qSOu5m9Pk0haZ3QFxausLhkZJm9UUFjx1u8SpTRAEQRAEYQhQWR8uY6tuTq/giZzD09qLHh6PL3pd2uDqXXmcEMsQETxmDqml+E0OCHigQaaNC4IgCIIgHO9EZniqWtIseNJU0tY5w9Pg8vT4XEJ8hobgsZhQMdGUXaFtqBXjAkEQBEEQhOOd6AxP+np4VFWNHjzaiwxPh2R4+pwhIXiyrGYA6p3jtQ3SxyMIgiAIgnDcE+nMVtPqwRcIdrF38rh9AbwR50prD88gdWkLBlV2VrcSDMbOnBvsDAnBYw8Jnhr7OG2DZHgEQRAEQRCOa4JBlcoIwaOqmuhJB5HlbKAJnkAPhUBMSdsgNS14YnMli+5bxy9XZl7iICXBs3z5ck477TRyc3MZNmwYl112GTt37uzymL/97W+cc845FBYWUlhYyPz589m8eXOvgk4Vh1V7mtX2Cm2DZHgEQegh48eP57777ktqX0VReOGFF/o0HkEQBCE+1S0deP1BLCaF8nyHti1NZW26Q1uuPWx47PL2LMsTW9I2OAXPfz84CsBDG/azv87Vzd6Di5QEzxtvvMGNN97I22+/zerVq/H5fCxcuBCXK/GTXrt2LVdddRWvv/46GzduZPTo0SxcuJAjR470Ovhk0UvaDlvHahvqd0NAptgKgiAIgiAcrxwM9e+MKsxiVGEWkD5raj3DMyzPjs2sLad72seTCSVtbR4/71U2AuAPqvzq5cxKHqQ0h2flypVRtx955BGGDRvGli1bmDdvXtxjHn/88ajbf//733n22WdZs2YNS5YsSTHcnmG3aG/EY8owsDrB1w4N+6B0cr88viAIgiAIgtC/HAw5tI0tziY/ywo0ps2autmtiZL8LCuNDh8NLm+P+3h0W+pch4XWDv+gLGl7e289voBKodNKs9vHyk+qefdAA6dWFA10aEnRqx6e5uZmAIqKkn+y7e3t+Hy+lI7pLVk2LcPj9qtQOkXbKH08gpBeVBW8ruR/fO2p7Z/oR02+Zvqvf/0rI0aMIBiMvpp26aWXct1117F3714uvfRSysrKyMnJ4bTTTuPVV19N20v00UcfccEFF5CVlUVxcTHXX389bW1txv1r167l9NNPJzs7m4KCAubOncvBgwcB+OCDDzj//PPJzc0lLy+PU045hXfffTdtsQmCIBxv6IYFY4udRklbVdoEj5bhKXDayAmVtfV0Fk9HKMOjx9js9uFPk7lCuli3uxaAxSeUc+VpowH4+YrtqCl8Bw8kKWV4IgkGg3znO99h7ty5zJw5M+njvve97zFixAjmz5+fcB+Px4PHE24qa2lpAcDn8+HzpW7VZ1W0f91eP8GSKZiOvk+g+hOCkxanfK7+RH+uPXnOA0UmxgwSd08eV1VVgsFgWDx4XZh+OSqp401AQZpiCX7/MNiyk9r3c5/7HDfffDNr1qzhwgsvBKChoYGVK1fy4osv0tLSwkUXXcRPf/pT7HY7//znP7nkkkvYvn07o0ePNs6jP/ek4gu9Ri6Xi0WLFnHmmWeyadMmampquP7667nxxht5+OGH8fv9XHbZZXzta1/j8ccfx+v1snnzZuOxrr76ak466STuv/9+zGYzW7duxWw2dxuH/mXUVczBYBBVVfH5fJjN5qj7Mu3/hCAIgo5uST22OBtTaC1Y3ZKeHh69pK0gy2oInt5meMryHOw61oaqaqKnOMeelljTwbpdmuCZN7mU2aML+L+tR3m/sokVH1XzqRPLBzi67umx4Lnxxhv5+OOP2bBhQ9LH/PKXv+Spp55i7dq1OByOhPstX76cO++8M2b7qlWrcDqdKce6p0YBzByqOsZ2j8oMoPrD13m3dUbK5xoIVq9ePdAhpEwmxgwSd7JYLBaGDx9OW1sbXm8o9e5rT5uISYWW1lawBrrfETCbzcyfP59//OMfnHbaaQA89thjFBcXc8opp2AymRg3bpyx/6233sqzzz7Lv/71L66//npAEwcdHR3GhZjucLvdtLS08Oijj+J2u/nDH/5AdnY2Y8aM4Ze//CVXXXUVP/zhD7FarTQ3N3P++edTWloKwGc/+1ntOba0UFlZyY033siIESMAWLRokXFfMrS2tia8z+v14na7WbduHX5/9Bd2e3t7gqMEQRAGN/rQ0bFFTvwhB7W09fCEMjz5Tis5jpDg6WUPT7bNQn6WVjLW4PIOGsFTWd/Ogfp2LCaFsyYUk+uwcv288dz36m5+tXIH86cPw24xd3+iAaRHguemm27ixRdfZN26dYwaldwV3XvuuYdf/vKXvPrqq5x44old7rts2TKWLl1q3G5paTHMDvLy8lKO17/1ME/u3UZufhFTzrkMnn6aEdYWFi8e/Bme1atXs2DBAqxW60CHkxSZGDNI3KnS0dHBoUOHyMnJCV+8UHO1bEsSqKpKa1sbuTk5KIrSq1jyrE5I4RxLlizhG9/4Bn/961+x2+08//zzfPGLX6SgoIC2tjbuvPNOVqxYQVVVFX6/H7fbTW1tLbm5ubS2tmIymXA4HEl/FmVlZZGXl8eBAwc46aSTKC8PXwlbsGABwWCQo0ePMm/ePL7yla/wuc99jvnz5zN//nyuuOIKY//vfve7fPvb3+bZZ5/lwgsv5POf/zwTJkzo9vFVVaW1tZXc3NyEr3VHRwdZWVnMmzcv5mJUsoJKEARhMKGqakSGx0m7V7swlr4enpDgybIaTm1tnp5lxHWXNrvVRFG2zRA8gwW9nO3kMYXkOrS1xvXzxvPEpkoqG9p57O1Kvnr2uK5OMeCkJHhUVeXmm2/m+eefZ+3atVFXQrvi7rvv5uc//zmvvPIKp556arf72+127PZYVWu1Wnu0qMu22wDoCASxlGvld0r9XqwmwDz4F7c9fd4DSSbGDBJ3sgQCARRFwWQyYTJFtAKac5M6PhgMgieIYs+JPr4fuPTSS7n++ut5+eWXOe2001i/fj2//e1vMZlM/O///i+rV6/mnnvuYeLEiWRlZfH5z38en88XJRb0554M+mukHx95nP67vs8jjzzCLbfcwsqVK/nXv/7Fj3/8Y1avXs2ZZ57JnXfeydVXX81LL73Eyy+/zB133MFTTz1lZIESoZexdRWzHl+891Em/n8QBGFwU93cwRV/eYsvnjaGG8+f2CeP0djuo9XjR1FgdJGTlpBAqWntwB8IYjH37runObKkzdG7Hh49w+OwmCnKtrG/zkVjPxsXPPfeYX776i7uu3I2p4wtjLpPL2c7Z1KJsc1ps7B0wWS+/9xH/H7Nbq46fTROW48Lx/qclP7aN954I4899hhPPPEEubm5VFdXU11djdsdrodcsmQJy5YtM27/6le/4sc//jEPPfQQFRUVxjGRjbp9jSNkWuDxBSF/NNhyIOiD+r39FoMgCIMDh8PB5ZdfzuOPP86TTz7JlClTOPnkkwF48803ueaaa/jsZz/LCSecwPDhwzlw4EBaHnfatGl88MEHUTb+b775JiaTiSlTphjbZs+ezbJly3jrrbeYOXMmTzzxhHHf5MmT+e53v8uqVau4/PLLefjhh9MSmyAIQn+y+UADhxrc/N/WvhtRopezDc9z4LCaKcmxYzEpBNM0fLQp5NJW4LSRmybBY7eaKHRqF+kbXP3bP/nih1UcanDzoxc+jhqg6gsEeWtvPaD170RyxamjDde2wT6XJyXB8+c//5nm5mbOO+88ysvLjZ+nn37a2KeyspKqqqqoY7xeL5///OejjrnnnnvS9yy6wRGype7wBbXSF3FqE4QhjZ4peeihh7j66quN7ZMmTeK5555j69atfPDBB3zpS19K2pwgmcd0OBx85Stf4eOPP+b111/n5ptv5n/+538oKytj//79LFu2jI0bN3Lw4EFWrVrF7t27mTZtGm63m5tuuom1a9dy8OBB3nzzTd555x2mTZuWltgEQRD6E70crCpN/TTx0MvZxhRpvd8mk0JZXvqc2nTTgvwsKzl2LRPeW9MCu8VEUbZ2rgZX70VZKtSGROD2qhaefz8sRLceaqLN46fQaWXmyPyoY8wmhWG52mva2M8CLVVSLmnrjrVr10bdTtfV0d7gCA0eNSbZlk6DI1ugZgdkhm+BIAhp5IILLqCoqIidO3fypS99ydh+7733ct1113HWWWdRUlLC9773vbT1sDidTl555RVuueUWTjvtNJxOJ5/73Oe49957jft37NjBo48+Sn19PeXl5dx444184xvfwO/3U19fz5IlSzh27BglJSVcfvnlcc1dBEEQBjvNoXKtVo+f1g6f0ReSTvShoxXFYRfP8nwHR5rcaenjaY4wLchNk2mB3WKmMFsrf+7vDE9tRNbrnld28qkTysmymY1ytrMnlWI2xfaBFmVrGan6fhZoqTJ4i+3SiCF4/CHBM2yq9q9keARhSGIymTh69GjM9oqKCl577bWobTfeeCMQ7oXZt29f0v07nS8SnXDCCTHn1ykrK+P555+Pe5/NZuPJJ59M6jEFQRAGO3p2BOBYS0cfCR6txGpMcdjdt7wgCw42UtXce2vq5nTaUofWpw6riTyLdq7+7OEJBlVDsORnWalu6eChN/dz4/kT4/bv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s5Gamsq0adMoLy8HwOPx8NBDDzF48GCsVit9+/blvvvuCzuezkQEjyAIUcGQ7AQARniHcoaLv2lB5Je0CT0Tu9PDQE3wpA3u5mgE4ShAUcBR2/qPs67tdcL58c5Ta4tf/vKXlJaW8tVXX+nPlZWVsXDhQi677DJqamqYMWMGixcvZu3atZx99tmce+65HDhwIKy3xGg08s9//pNNmzbxyiuvsGTJEv785z/ry9etW8fkyZMZOXIkK1as4Ntvv2XmzJm43eocsblz5/LAAw9wxx13sHnzZt544w2ys7PDiqWzkZI2QRCigrtmjuKK/P4Mz0ls136a2lILQndgd7kZZNQc2iTDIwidjrMO7u/V4mIjkNJZx/7LYbDEt7laamoq06dP54033mDy5MkAvPvuu2RkZHDGGWdgNBoZO3asvv7f//533n//fT777DNGjRoVclg33XST/v/+/ftz7733MmvWLJ5++mkAHnroISZMmKA/BvTjVFdX88QTT/Cvf/2LK6+8EoBBgwZx8sknhxxHVyAZHkEQooJYs4kRuUntnptj9Qoes8lAegQOHRWODjwN1eQaygDJ8AiC0Mhll13G//73P+x2OwCvv/46v/rVrzAajdTU1HDLLbcwYsQIUlJSSEhIYMuWLRw8eDCsY3355ZdMnjyZ3r17k5iYyOWXX05paSl1dXVAY4YnEFu2bMFut7e4PNKQDI8gCEcVWklbTnIsRqO0igvdQ0r9PgAqDMnEx6V0bzCCcDRgtqmZlhbweDxUVVeTlJiI0djB+QCzLehVZ86ciaIofPrppxx//PF88803/OMf/wDglltuYdGiRTzyyCMMHjyYuLg4LrzwQpxOZ8gh7d27l5/97Gdcd9113HfffaSlpfHtt9/ym9/8BofDgc1mIy6u5bLv1pZFIpLhEQThqMLqNS3ITYquP9ZC2zz11FP079+f2NhYJk2axPfff9/iups2beIXv/gF/fv3x2AwdPncinP7qHdQXfE5XXpcQThqMRjUsrLWfsy2ttcJ5yeEyoTY2FguuOACXn/9dd58802GDRvGcccdB6gGAldddRXnn38+o0ePJicnh71794b1dqxZswaPx8Ojjz7KCSecwNChQzl82F8QjhkzhsWLFwfcfsiQIcTFxbW4PNIQwSMIwlHFwAy1jvqY3sndHInQkbz11lvMmTOHu+66ix9/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",
      "text/plain": [
       "<Figure size 1000x500 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "#画线要注意的是损失是不一定在零到1之间的\n",
    "def plot_learning_curves(record_dict, sample_step=500):\n",
    "    # build DataFrame\n",
    "    train_df = pd.DataFrame(record_dict[\"train\"]).set_index(\"step\").iloc[::sample_step]\n",
    "    val_df = pd.DataFrame(record_dict[\"val\"]).set_index(\"step\")\n",
    "\n",
    "    # plot\n",
    "    fig_num = len(train_df.columns)\n",
    "    fig, axs = plt.subplots(1, fig_num, figsize=(5 * fig_num, 5))\n",
    "    for idx, item in enumerate(train_df.columns):    \n",
    "        axs[idx].plot(train_df.index, train_df[item], label=f\"train_{item}\")\n",
    "        axs[idx].plot(val_df.index, val_df[item], label=f\"val_{item}\")\n",
    "        axs[idx].grid()\n",
    "        axs[idx].legend()\n",
    "        # axs[idx].set_xticks(range(0, train_df.index[-1], 5000))\n",
    "        # axs[idx].set_xticklabels(map(lambda x: f\"{int(x/1000)}k\", range(0, train_df.index[-1], 5000)))\n",
    "        axs[idx].set_xlabel(\"step\")\n",
    "    \n",
    "    plt.show()\n",
    "\n",
    "plot_learning_curves(record, sample_step=100)  #横坐标是 steps"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 评估"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {
    "ExecutionIndicator": {
     "show": true
    },
    "execution": {
     "iopub.execute_input": "2025-02-04T11:58:32.723913Z",
     "iopub.status.busy": "2025-02-04T11:58:32.723403Z",
     "iopub.status.idle": "2025-02-04T11:58:33.753783Z",
     "shell.execute_reply": "2025-02-04T11:58:33.752441Z",
     "shell.execute_reply.started": "2025-02-04T11:58:32.723877Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "loss:     0.8531\n",
      "accuracy: 0.7008\n"
     ]
    }
   ],
   "source": [
    "# dataload for evaluating\n",
    "\n",
    "# load checkpoints\n",
    "model.load_state_dict(torch.load(f\"checkpoints/{exp_name}/best.ckpt\",weights_only=True, map_location=\"cpu\"))\n",
    "\n",
    "model.eval()\n",
    "loss, acc = evaluating(model, eval_dl, loss_fct)\n",
    "print(f\"loss:     {loss:.4f}\\naccuracy: {acc:.4f}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### fine—tunign 精调"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {
    "ExecutionIndicator": {
     "show": true
    },
    "execution": {
     "iopub.execute_input": "2025-02-04T11:58:36.047119Z",
     "iopub.status.busy": "2025-02-04T11:58:36.046555Z",
     "iopub.status.idle": "2025-02-04T12:00:26.366088Z",
     "shell.execute_reply": "2025-02-04T12:00:26.364998Z",
     "shell.execute_reply.started": "2025-02-04T11:58:36.047077Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "100%|██████████| 7040/7040 [01:50<00:00, 63.83it/s, epoch=9]\n"
     ]
    }
   ],
   "source": [
    "model = VGG.from_pretrained(\"checkpoints/vgg-fine-tune/best.ckpt\",num_classes=10)\n",
    "# 微调（Fine-tuning）：在迁移学习或微调预训练模型时，这种方法特别有用。\n",
    "# 在这种情况下，你可能希望对模型的预训练部分（不包含\"cls\"的部分）使用较小的学习率，以避免破坏已经学到的特征。\n",
    "# 而对新添加的或需要特别训练的部分（如新的分类层，包含\"cls\"的部分）使用较高的学习率，以便更快地学习到特定任务的特征。\n",
    "optimizer = torch.optim.Adam(\n",
    "    [\n",
    "        {\n",
    "            \"params\": [value for key, value in model.named_parameters() if \"cls\" not in key and \"model.12\" not in key and \"model.10\" not in key],\n",
    "            \"lr\": 0.0001  # 卷积用的是预训练的参数，学习率要小一点\n",
    "        },\n",
    "    \n",
    "        {\n",
    "            \"params\": [value for key, value in model.named_parameters() if \"model.10\" in key],  # 这里是倒数第三层\n",
    "            \"lr\": 0.0003\n",
    "        },\n",
    "        {\n",
    "            \"params\": [value for key, value in model.named_parameters() if \"model.12\" in key],  # 这里是倒数第二层\n",
    "            \"lr\": 0.0005\n",
    "        },\n",
    "        {\n",
    "            \"params\": [value for key, value in model.named_parameters() if \"cls\" in key],  # 这里是全连接层\n",
    "            \"lr\": 0.0007\n",
    "        },\n",
    "     ]\n",
    "    )\n",
    "\n",
    "early_stop_callback = EarlyStopCallback(patience=5)\n",
    "model = model.to(device)\n",
    "record = training(\n",
    "    model, \n",
    "    train_dl, \n",
    "    eval_dl, \n",
    "    epoch, \n",
    "    loss_fct, \n",
    "    optimizer, \n",
    "    save_ckpt_callback=save_ckpt_callback,\n",
    "    early_stop_callback=early_stop_callback,\n",
    "    eval_step=len(train_dl)\n",
    "    )"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {
    "ExecutionIndicator": {
     "show": false
    },
    "execution": {
     "iopub.execute_input": "2025-02-04T11:43:26.799319Z",
     "iopub.status.busy": "2025-02-04T11:43:26.798778Z",
     "iopub.status.idle": "2025-02-04T11:43:27.844896Z",
     "shell.execute_reply": "2025-02-04T11:43:27.843620Z",
     "shell.execute_reply.started": "2025-02-04T11:43:26.799276Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "loss:     0.7901\n",
      "accuracy: 0.7298\n"
     ]
    }
   ],
   "source": [
    "plot_learning_curves(record, sample_step=100)  #横坐标是 steps\n",
    "\n",
    "# dataload for evaluating\n",
    "\n",
    "# load checkpoints\n",
    "model.load_state_dict(torch.load(f\"checkpoints/{exp_name}/best.ckpt\",weights_only=True, map_location=\"cpu\"))\n",
    "\n",
    "model.eval()\n",
    "loss, acc = evaluating(model, eval_dl, loss_fct)\n",
    "print(f\"loss:     {loss:.4f}\\naccuracy: {acc:.4f}\")"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.14"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
